%locations
%{
#include "lex.yy.c"
extern int yylineno;
extern tree_t mTreeRoot;
int syntaxError = 0;
int BRACE = 0, PAREN = 0, BRACKET = 0;
void yyerror(const char *s);
void syntaxPrint(const char *s){
#ifdef LOCAL
	fprintf(stderr, "syntaxPrint: Line %d:  %s.\n", yylineno, s);
#endif
}
%}
/* declared yylval types */
%union{
	tree_node_t * node;
}

%token <node>INT FLOAT ID
%token <node>SEMI COMMA 
%token <node>TYPE

%right <node>ASSIGN
%left  <node>RELOP
%left  <node>PLUS MINUS MUL DIV
%left  <node>AND OR 
%left  <node>DOT
%right <node>NOT
%left <node>LP RP LB RB 
%token <node>LC RC
%token <node>STRUCT
%token <node>RETURN
%token <node>IF ELSE
%token <node>WHILE

%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE

/* define type  */
%type <node>Program
%type <node>ExtDecList
%type <node>ExtDef
%type <node>ExtDefList
%type <node>Specifier
%type  <node>StructSpecifier
%type <node>OptTag
%type  <node>Tag
%type <node> VarDec
%type  <node>FunDec
%type  <node>VarList
%type <node>ParamDec
%type <node> CompSt
%type  <node>StmtList
%type  <node>Stmt
%type <node>DefList
%type <node>Def
%type <node>DecList
%type <node>Dec
%type <node>Exp
%type <node>Args

%%
// High-level definitions
Program: ExtDefList {
	;
	syntaxPrint("Program");
}
	;
ExtDefList: ExtDef ExtDefList 
	| /* empty */ 
	;
ExtDef: Specifier ExtDecList SEMI
	| Specifier SEMI
	| Specifier FunDec CompSt
	| error SEMI
	| Specifier error SEMI
	| error Specifier SEMI
	;
ExtDecList: VarDec
	| VarDec COMMA ExtDecList
	| VarDec error ExtDecList
	| error
	;
// Specifier: TYPE
Specifier: TYPE
	| StructSpecifier
	| error
	;
StructSpecifier: STRUCT OptTag LC DefList RC
	| STRUCT Tag
	;
OptTag: ID
	| /* empty */
	;
Tag: ID
	;
// Declarators
VarDec: ID
	| VarDec LB INT RB
	| VarDec LB error RB
	;
FunDec: ID LP VarList RP
	| ID LP RP
	| error LP VarList RP
	;
VarList: ParamDec COMMA VarList
	| ParamDec
	| error
	;
ParamDec: Specifier VarDec
	;
// Statements
CompSt: LC DefList StmtList RC
	;
StmtList: Stmt StmtList
	| /* empty */
	;
Stmt: Exp SEMI
	| CompSt
	| RETURN Exp SEMI
	| IF LP Exp RP Stmt %prec LOWER_THAN_ELSE
	| IF LP Exp RP Stmt ELSE Stmt
	| WHILE LP Exp RP Stmt
	| error SEMI
	| Exp error SEMI
	| RETURN Exp error
	;
// Local Definitions
DefList: Def DefList
	| /* empty */
	;
Def: Specifier DecList SEMI
	|Specifier DecList error
	;
DecList: Dec
	| Dec COMMA DecList
	;
Dec: VarDec
	| VarDec ASSIGN Exp
	;
// Expressions
// 在表达式层面，对error兜底
Exp: Exp ASSIGN Exp
	| Exp AND Exp
	| Exp OR Exp
	| Exp RELOP Exp
	| Exp PLUS Exp
	| Exp MINUS Exp
	| Exp MUL Exp
	| Exp DIV Exp
	| LP Exp RP
	| MINUS Exp
	| NOT Exp
	| ID LP Args RP
	| ID LP RP
	| Exp LB Exp RB
	| Exp DOT ID // 不甚理解
	| ID
	| INT
	| FLOAT
	| ID error
	| INT error
	| FLOAT error
	| error
	;
Args: Exp COMMA Args
	| Exp
	;
%%
void yyerror(const char *s) {
	syntaxError += 1;
    printf("Error type B at Line %d:  %s.\n", yylineno, s);
}
